﻿//========================================
// All rights reserved (C) 2017-2100
// CLR 版本：	4.0.30319.42000
// 命名空间:	SFJDService.SocketHandle
// 文 件 名：	PacketFileTransport
// 作    者：	WooG
// 联系方式：	wooglle@163.com
// 创建时间：	2018/6/17 14:40:56
//========================================
using System;
using System.Linq;
using System.Security.Cryptography;

namespace SFJDService.TransportHandle
{
    public struct PacketFileTransport
    {
        public const int BytesCount = 512;
        public const int HeadCount = 18;
        public const int FileByteCount = BytesCount - HeadCount;
        internal int ByteIndex { set; get; }
        internal int ByteIndexTotal { set; get; }
        internal Int16 Hash { set; get; }
        internal int FileIndex { set; get; }
        internal int Length { set; get; }
        internal byte[] Bytes { set; get; }

        public PacketFileTransport(int fileIndex, int index, int indextotal, byte[] fileBytes)
        {
            ByteIndex = index;
            ByteIndexTotal = indextotal;
            Hash = GetHash(fileBytes);
            FileIndex = fileIndex;
            Length = fileBytes.Length;
            Bytes = fileBytes;
        }

        public PacketFileTransport(byte[] bytes)
        {
            ByteIndex = BitConverter.ToInt32(bytes.Take(4).ToArray(), 0);
            ByteIndexTotal = BitConverter.ToInt32(bytes.Skip(4).Take(4).ToArray(), 0);
            Hash = BitConverter.ToInt16(bytes.Skip(8).Take(2).ToArray(), 0);
            FileIndex = BitConverter.ToInt32(bytes.Skip(10).Take(4).ToArray(), 0);
            Length = BitConverter.ToInt32(bytes.Skip(14).Take(4).ToArray(), 0);
            Bytes = bytes.Skip(18).Take(Length).ToArray();
        }

        public byte[] ToBytes()
        {
            byte[] b = new byte[BytesCount];
            Buffer.BlockCopy(BitConverter.GetBytes(ByteIndex), 0, b, 0, 4);
            Buffer.BlockCopy(BitConverter.GetBytes(ByteIndexTotal), 0, b, 4, 4);
            Buffer.BlockCopy(BitConverter.GetBytes(Hash), 0, b, 8, 2);
            Buffer.BlockCopy(BitConverter.GetBytes(FileIndex), 0, b, 10, 4);
            Buffer.BlockCopy(BitConverter.GetBytes(Length), 0, b, 14, 4);
            Buffer.BlockCopy(Bytes, 0, b, 18, Length);
            return b;
        }

        public bool Check()
        {
            return Hash == GetHash(Bytes);
        }

        public override bool Equals(object obj)
        {
            if (!(obj is PacketFileTransport))
            {
                return false;
            }

            var transport = (PacketFileTransport)obj;
            return ByteIndex == transport.ByteIndex &&
                   ByteIndexTotal == transport.ByteIndexTotal &&
                   Hash == transport.Hash &&
                   FileIndex == transport.FileIndex &&
                   Length == transport.Length;
        }

        public override int GetHashCode()
        {
            var hashCode = -50788344;
            hashCode = hashCode * -1521134295 + base.GetHashCode();
            hashCode = hashCode * -1521134295 + ByteIndex.GetHashCode();
            hashCode = hashCode * -1521134295 + ByteIndexTotal.GetHashCode();
            hashCode = hashCode * -1521134295 + Hash.GetHashCode();
            hashCode = hashCode * -1521134295 + FileIndex.GetHashCode();
            hashCode = hashCode * -1521134295 + Length.GetHashCode();
            return hashCode;
        }

        public override string ToString()
        {
            return FileIndex + ": " + ByteIndex + "/" + ByteIndexTotal + ", " + Length + ", " + Hash;
        }

        public static bool operator ==(PacketFileTransport transport1, PacketFileTransport transport2)
        {
            return transport1.Equals(transport2);
        }

        public static bool operator !=(PacketFileTransport transport1, PacketFileTransport transport2)
        {
            return !(transport1 == transport2);
        }

        private static Int16 GetHash(byte[] bytes)
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] retVal = md5.ComputeHash(bytes);
            return BitConverter.ToInt16(retVal, 0);
        }
    }
}
